import React, { Component, ErrorInfo, ReactNode } from 'react';
import {
  ExclamationTriangleIcon,
  ArrowPathIcon,
} from '@heroicons/react/24/outline';

interface Props {
  children: ReactNode;
  fallback?: ReactNode;
  onError?: (error: Error, errorInfo: ErrorInfo) => void;
}

interface State {
  hasError: boolean;
  error: Error | null;
  errorInfo: ErrorInfo | null;
}

export class ErrorBoundary extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      hasError: false,
      error: null,
      errorInfo: null,
    };
  }

  static getDerivedStateFromError(error: Error): State {
    return {
      hasError: true,
      error,
      errorInfo: null,
    };
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    this.setState({
      error,
      errorInfo,
    });

    // 调用错误回调
    this.props.onError?.(error, errorInfo);

    // 记录错误到控制台
    console.error('ErrorBoundary caught an error:', error, errorInfo);

    // 可以在这里发送错误报告到服务器
    this.logErrorToService(error, errorInfo);
  }

  private logErrorToService = (error: Error, errorInfo: ErrorInfo) => {
    // 这里可以集成错误报告服务
    const errorReport = {
      message: error.message,
      stack: error.stack,
      componentStack: errorInfo.componentStack,
      timestamp: new Date().toISOString(),
      userAgent: navigator.userAgent,
      url: window.location.href,
    };

    // 发送到日志服务或本地存储
    try {
      localStorage.setItem(`error_${Date.now()}`, JSON.stringify(errorReport));
    } catch (e) {
      console.error('Failed to log error:', e);
    }
  };

  private handleRetry = () => {
    this.setState({
      hasError: false,
      error: null,
      errorInfo: null,
    });
  };

  private handleReload = () => {
    window.location.reload();
  };

  render() {
    if (this.state.hasError) {
      // 如果提供了自定义 fallback，使用它
      if (this.props.fallback) {
        return this.props.fallback;
      }

      // 默认错误 UI
      return (
        <div className="flex min-h-screen items-center justify-center bg-gray-50 dark:bg-gray-900">
          <div className="w-full max-w-md rounded-lg bg-white p-6 shadow-lg dark:bg-gray-800">
            <div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-red-100 dark:bg-red-900">
              <ExclamationTriangleIcon className="h-6 w-6 text-red-600 dark:text-red-400" />
            </div>

            <h1 className="mb-2 text-center text-xl font-semibold text-gray-900 dark:text-white">
              出现了一个错误
            </h1>

            <p className="mb-6 text-center text-gray-600 dark:text-gray-400">
              应用程序遇到了意外错误。您可以尝试重新加载页面或重启应用程序。
            </p>

            {/* 错误详情（开发模式下显示） */}
            {import.meta.env.DEV && this.state.error && (
              <details className="mb-4 rounded bg-gray-100 p-3 text-sm dark:bg-gray-700">
                <summary className="mb-2 cursor-pointer font-medium text-gray-700 dark:text-gray-300">
                  错误详情
                </summary>
                <div className="whitespace-pre-wrap font-mono text-xs text-red-600 dark:text-red-400">
                  {this.state.error.message}
                  {this.state.error.stack && (
                    <div className="mt-2 border-t border-gray-300 pt-2 dark:border-gray-600">
                      {this.state.error.stack}
                    </div>
                  )}
                </div>
              </details>
            )}

            <div className="flex space-x-3">
              <button
                onClick={this.handleRetry}
                className="flex flex-1 items-center justify-center rounded-md bg-blue-600 px-4 py-2 text-white transition-colors hover:bg-blue-700"
              >
                <ArrowPathIcon className="mr-2 h-4 w-4" />
                重试
              </button>

              <button
                onClick={this.handleReload}
                className="flex-1 rounded-md bg-gray-600 px-4 py-2 text-white transition-colors hover:bg-gray-700"
              >
                重新加载
              </button>
            </div>

            <div className="mt-4 text-center text-xs text-gray-500 dark:text-gray-400">
              如果问题持续存在，请联系技术支持
            </div>
          </div>
        </div>
      );
    }

    return this.props.children;
  }
}

// 函数式组件版本的错误边界 Hook
export function useErrorHandler() {
  const handleError = React.useCallback(
    (error: Error, errorInfo?: ErrorInfo) => {
      console.error('Error caught by error handler:', error, errorInfo);

      // 记录错误
      const errorReport = {
        message: error.message,
        stack: error.stack,
        timestamp: new Date().toISOString(),
        userAgent: navigator.userAgent,
        url: window.location.href,
      };

      try {
        localStorage.setItem(
          `error_${Date.now()}`,
          JSON.stringify(errorReport)
        );
      } catch (e) {
        console.error('Failed to log error:', e);
      }
    },
    []
  );

  return { handleError };
}

// 简化的错误边界组件
export function SimpleErrorBoundary({
  children,
  message = '出现了一个错误',
}: {
  children: ReactNode;
  message?: string;
}) {
  return (
    <ErrorBoundary
      fallback={
        <div className="rounded-md border border-red-200 bg-red-50 p-4 dark:border-red-800 dark:bg-red-900/20">
          <div className="flex items-center">
            <ExclamationTriangleIcon className="mr-2 h-5 w-5 text-red-500" />
            <p className="text-red-700 dark:text-red-400">{message}</p>
          </div>
        </div>
      }
    >
      {children}
    </ErrorBoundary>
  );
}

// 异步错误处理 Hook
export function useAsyncError() {
  const [, setError] = React.useState();

  return React.useCallback((error: Error) => {
    setError(() => {
      throw error;
    });
  }, []);
}

export default ErrorBoundary;
